package com.tssup.fesco.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.Socket;
import java.net.URL;
import java.net.URLEncoder;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 对Httpclient组件封装
 * @author Haijun
 * @date 2016年7月20日
 * @see 
 * @version
 */
public class HttpClientHelper {
    
	protected final static Logger logger = LoggerFactory.getLogger(HttpClientHelper.class);
	public static final String KEY_TRACE_ID = "traceId";
	
	private static class LazyHolder{
	        
	        private static final  HttpClientHelper client  ;
	        
	        static {
	            client = new HttpClientHelper() ;
	        }   
	}
	
	public  static final  HttpClientHelper getInstance(){
	        return LazyHolder.client ;    
	}
	
	private HttpClientHelper() {
	}
	/**
	 * 发送GET请求
	 * @param url
	 * @return
	 */
	// http://localhost:8080/RESTfulExample/json/product/get
	public static String get(String url) {
		try {
			DefaultHttpClient httpClient = new DefaultHttpClient();
			//HttpGet getRequest = new HttpGet("http://localhost:8080/RESTfulExample/json/product/get");
			HttpGet getRequest = new HttpGet(url);
			getRequest.addHeader("accept", "application/json");
//			getRequest.addHeader(KEY_TRACE_ID, HessianContext.getTraceId() + "");

			HttpResponse response = httpClient.execute(getRequest);

			if (response.getStatusLine().getStatusCode() != 200) {
				throw new RuntimeException("Failed : HTTP error code : " + response.getStatusLine().getStatusCode());
			}
			BufferedReader br = new BufferedReader(new InputStreamReader((response.getEntity().getContent())));

			String output;
		    StringBuilder sb = new StringBuilder();   
			System.out.println("Output from Server .... \n");
			while ((output = br.readLine()) != null) {
				//System.out.println(output);
				sb.append(output);
			}
			httpClient.getConnectionManager().shutdown();
			return sb.toString();
		} catch (ClientProtocolException e) {
			logger.error("发送GET请求失败", e);
		} catch (IOException e) {
			logger.error("读取POST请求响应数据失败", e);
		}
		return null;

	}
	/**
	 * 发送GET请求
	 * @param url
	 * @return
	 */
	// http://localhost:8080/RESTfulExample/json/product/get
	public static String getXml(String url) {
		try {
			DefaultHttpClient httpClient = new DefaultHttpClient();
			//HttpGet getRequest = new HttpGet("http://localhost:8080/RESTfulExample/json/product/get");
			HttpGet getRequest = new HttpGet(url);
			getRequest.addHeader("accept", "text/xml");
//			getRequest.addHeader(KEY_TRACE_ID, HessianContext.getTraceId() + "");

			HttpResponse response = httpClient.execute(getRequest);

			if (response.getStatusLine().getStatusCode() != 200) {
				throw new RuntimeException("Failed : HTTP error code : " + response.getStatusLine().getStatusCode());
			}
			BufferedReader br = new BufferedReader(new InputStreamReader((response.getEntity().getContent())));

			String output;
		    StringBuilder sb = new StringBuilder();   
			System.out.println("Output from Server .... \n");
			while ((output = br.readLine()) != null) {
				//System.out.println(output);
				sb.append(output);
			}
			httpClient.getConnectionManager().shutdown();
			return sb.toString();
		} catch (ClientProtocolException e) {
			logger.error("发送GET请求失败", e);
		} catch (IOException e) {
			logger.error("读取POST请求响应数据失败", e);
		}
		return null;

	}
	/**
	 * 发送post请求
	 * @param url 请求地址 
	 * @param json 请求体，格式为json字符串
	 * @return
	 */
	// http://localhost:8080/RESTfulExample/json/product/post
	public static String post(String url, String json, String... contenttype) {

		try {
			DefaultHttpClient httpClient = new DefaultHttpClient();
			HttpPost postRequest = new HttpPost(url);
//			postRequest.addHeader(KEY_TRACE_ID, HessianContext.getTraceId() + "");
			StringEntity input = new StringEntity(json,"UTF-8");
			if(null != contenttype && contenttype.length>0){
				input.setContentType(contenttype[0]);
			}else{
				input.setContentType("application/json");
			}
			input.setContentEncoding("UTF-8");
			postRequest.setEntity(input);
			HttpResponse response = httpClient.execute(postRequest);

//			if (response.getStatusLine().getStatusCode() != 201) {
//				throw new RuntimeException("Failed : HTTP error code : " + response.getStatusLine().getStatusCode());
//			}
			BufferedReader br = new BufferedReader(new InputStreamReader((response.getEntity().getContent())));

			String output;
			StringBuilder sb = new StringBuilder();   
			System.out.println("Output from Server .... \n");
			while ((output = br.readLine()) != null) {
				//System.out.println(output);
				sb.append(output);
			}
			httpClient.getConnectionManager().shutdown();
			return sb.toString();
		} catch (MalformedURLException e) {
			logger.error("发送POST请求失败", e);
		} catch (IOException e) {
			logger.error("读取POST请求响应数据失败", e);
		}
		return null;
	}
	/**
	 * 发送post请求
	 * @param urlStr 请求地址
	 * @param xmlInfo, string
	 * @return
	 */
	// http://localhost:8080/RESTfulExample/json/product/post
	public static String postXml(String urlStr, String xmlInfo) {

		StringBuffer sb=new StringBuffer();
		try{
			URL url = new URL(urlStr);
			HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
			connection.setDoOutput(true);
			connection.setDoInput(true);
			connection.setUseCaches(false);
			connection.setRequestMethod("POST");
			if (null != xmlInfo) {
				OutputStream outputStream = connection.getOutputStream();
				outputStream.write(xmlInfo.getBytes("UTF-8"));
				outputStream.close();
			}
			// 从输入流读取返回内容
			InputStream inputStream = connection.getInputStream();
			InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
			BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
			String str = null;
			while ((str = bufferedReader.readLine()) != null) {
				sb.append(str);
			}
			bufferedReader.close();
			inputStreamReader.close();
			inputStream.close();
			connection.disconnect();
		}catch(Exception ex){
			ex.printStackTrace();
		}
		return sb.toString();
	}


	public static String postForm(String url, Map<String, Object> params) {
		try {
			String charset = "UTF-8";
			String query = buildQuery(params, charset);
			HttpClient httpClient = newHttpsClient();
			HttpPost postRequest = new HttpPost(url);
			StringEntity input = new StringEntity(query);
			input.setContentType("application/x-www-form-urlencoded");
			postRequest.setEntity(input);
			HttpResponse response = httpClient.execute(postRequest);
			if (response.getStatusLine().getStatusCode() != 200) {
				throw new RuntimeException("Failed : HTTP error code : " + response.getStatusLine().getStatusCode());
			}
			BufferedReader br = new BufferedReader(new InputStreamReader((response.getEntity().getContent())));

			String output;
			StringBuilder sb = new StringBuilder();
			while ((output = br.readLine()) != null) {
				sb.append(output);
			}
			httpClient.getConnectionManager().shutdown();
			return sb.toString();
		} catch (IOException e) {
			logger.error(e.getMessage(), e);
		}
		return null;
	}


	private static String buildQuery(Map<String, Object> params, String charset) throws IOException {
		if (params == null || params.isEmpty()) {
			return null;
		}

		StringBuilder query = new StringBuilder();
		Set<Entry<String, Object>> entries = params.entrySet();
		boolean hasParam = false;

		for (Entry<String, Object> entry : entries) {
			String name = entry.getKey();
			String value = (String) entry.getValue();
			if (StringUtils.isNotEmpty(name) && StringUtils.isNotEmpty(value)) {
				if (hasParam) {
					query.append("&");
				} else {
					hasParam = true;
				}
				query.append(name).append("=").append(URLEncoder.encode(value, charset));
			}
		}

		return query.toString();
	}

	/**
	 * 发起https请求并获取结果
	 * @param requestUrl 请求地址
	 * @param requestMethod 请求方式（GET、POST）
	 * @param outputStr 提交的数据
	 * @return XML
	 */
	public static Map<String, String> httpRequestXML(String requestUrl, String requestMethod, String outputStr) {
		StringBuffer buffer = new StringBuffer();
		// 将解析结果存储在HashMap中
		Map<String, String> map = new HashMap<String, String>();
		try {
			// 创建SSLContext对象，并使用我们指定的信任管理器初始化
			TrustManager[] tm = { new MyX509TrustManager() };
			SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
			sslContext.init(null, tm, new java.security.SecureRandom());
			// 从上述SSLContext对象中得到SSLSocketFactory对象
			javax.net.ssl.SSLSocketFactory ssf = sslContext.getSocketFactory();

			URL url = new URL(requestUrl);
			HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
			httpUrlConn.setSSLSocketFactory(ssf);

			httpUrlConn.setDoOutput(true);
			httpUrlConn.setDoInput(true);
			httpUrlConn.setUseCaches(false);
			// 设置请求方式（GET/POST）
			httpUrlConn.setRequestMethod(requestMethod);

			if ("GET".equalsIgnoreCase(requestMethod)) {
				httpUrlConn.connect();
			}
			// 当有数据需要提交时
			if (null != outputStr) {
				OutputStream outputStream = httpUrlConn.getOutputStream();
				// 注意编码格式，防止中文乱码
				outputStream.write(outputStr.getBytes("UTF-8"));
				outputStream.close();
			}

			// 将返回的输入流转换成字符串
			InputStream inputStream = httpUrlConn.getInputStream();
			
			// 读取输入流
			SAXReader reader = new SAXReader();
			org.dom4j.Document document = reader.read(inputStream);
			System.out.println("接收的XML数据为:\n"+document.getText());
			// 得到xml根元素
			Element root = document.getRootElement();
			// 得到根元素的所有子节点
			List<Element> elementList = root.elements();

			// 遍历所有子节点
			for (Element e : elementList) {
				map.put(e.getName(), e.getText());
			}
			// 释放资源
			inputStream.close();
			inputStream = null;
			httpUrlConn.disconnect();
		}catch (Exception e) {
			System.out.println("https request error: " + e);
		}
		return map;
	}
	static public HttpClient newHttpsClient() {  
        try {  
            KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());  
            trustStore.load(null, null);  
  
            SSLSocketFactory sf = new MySSLSocketFactory(trustStore);  
            sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);  
  
            HttpParams params = new BasicHttpParams();  
            HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);  
            HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);  
            HttpConnectionParams.setConnectionTimeout(params, 10000);  
            HttpConnectionParams.setSoTimeout(params, 10000);  
  
            SchemeRegistry registry = new SchemeRegistry();  
            registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));  
            registry.register(new Scheme("https", sf, 443));  
  
            ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);  
  
            return new DefaultHttpClient(ccm, params);  
        } catch (Exception e) {  
            return new DefaultHttpClient();  
        }  
    }  
  
    private static class MySSLSocketFactory extends SSLSocketFactory {  
        SSLContext sslContext = SSLContext.getInstance("TLS");  
  
        public MySSLSocketFactory(KeyStore truststore)  
                throws NoSuchAlgorithmException, KeyManagementException,  
                KeyStoreException, UnrecoverableKeyException {  
            super(truststore);  
  
            TrustManager tm = new X509TrustManager() {  
                @Override
				public void checkClientTrusted(X509Certificate[] chain, String authType)
                        throws CertificateException {  
                }  
  
                @Override
				public void checkServerTrusted(X509Certificate[] chain, String authType)
                        throws CertificateException {  
                }  
  
                @Override
				public X509Certificate[] getAcceptedIssuers() {
                    return null;  
                }  
            };  
  
            sslContext.init(null, new TrustManager[] { tm }, null);  
        }  
  
        @Override  
        public Socket createSocket(Socket socket, String host, int port, boolean autoClose)  
                throws IOException, UnknownHostException {  
            return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);  
        }  
  
        @Override  
        public Socket createSocket() throws IOException {  
            return sslContext.getSocketFactory().createSocket();  
        }  
    }  
    public static String doPost(String url,Map<String,String> map,String charset){  
        HttpClient httpClient = null;  
        HttpPost httpPost = null;  
        String result = null;  
        try{  
        	httpClient = newHttpsClient();
            httpPost = new HttpPost(url);
//			httpPost.addHeader(KEY_TRACE_ID, HessianContext.getTraceId() + "");
            //设置参数  
            List<NameValuePair> list = new ArrayList<NameValuePair>();  
            Iterator iterator = map.entrySet().iterator();  
            while(iterator.hasNext()){  
                Entry<String,String> elem = (Entry<String, String>) iterator.next();  
                list.add(new BasicNameValuePair(elem.getKey(),elem.getValue()));  
            }  
            if(list.size() > 0){  
                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list,charset);  
                httpPost.setEntity(entity);  
            }  
            HttpResponse response = httpClient.execute(httpPost);
            if(response != null){  
                HttpEntity resEntity = response.getEntity();  
                if(resEntity != null){  
                    result = EntityUtils.toString(resEntity,charset);  
                }  
            }  
        }catch(Exception ex){  
            ex.printStackTrace();  
        }  
        return result;  
    }


	public static void main(String[] args) {
		String rsult = postXml("https://api.mch.weixin.qq.com/pay/unifiedorder","");
		System.out.println("返回结果："  +rsult);
	}

}
